package com.one.blocks.jdbc.meta.dialect;

import com.one.blocks.jdbc.meta.CatalogMeta;
import com.one.blocks.jdbc.meta.ColumnMeta;
import com.one.blocks.jdbc.meta.TableMeta;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

/**
 * @author <a href="mailto:idler41@163.con">linfuxin</a> created on 2024-07-16 19:57:02
 */
public interface MetaDialect {

    /**
     * 支持的数据库名称
     *
     * @return 数据库名称
     */
    String support();

    /**
     * 获取数据库产品名
     *
     * @param ds jdbc数据源
     * @return 数据库产品名
     */
    static String getDatabaseName(DataSource ds) {
        try (Connection con = ds.getConnection()) {
            return con.getMetaData().getDatabaseProductName().toLowerCase();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    default String getCurrentCatalog(DataSource ds) {
        try (Connection con = ds.getConnection()) {
            return con.getCatalog();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取数据库名
     *
     * @param ds jdbc数据源
     * @return 数据库名
     */
    default List<CatalogMeta> getCatalog(DataSource ds) {
        List<CatalogMeta> data = new ArrayList<>();
        try (Connection con = ds.getConnection()) {
            DatabaseMetaData metaData = con.getMetaData();
            try (ResultSet resultSet = metaData.getCatalogs()) {
                while (resultSet.next()) {
                    CatalogMeta entity = new CatalogMeta();
                    entity.setCatalogName(resultSet.getString("TABLE_CAT"));
                    data.add(entity);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return data;
    }

    /**
     * 指定数据库名获取表元数据
     *
     * @param ds      jdbc数据源
     * @param catalog 数据库名
     * @return 表元数据
     */
    List<TableMeta> getTable(DataSource ds, String catalog, Predicate<String> filter);

    /**
     * 指定数据库名与表获取列元数据
     *
     * @param ds             jdbc数据源
     * @param catalog        数据库名
     * @param tableName      表名
     * @param needColumnType 是否需要查询columnType(有额外sql查询消耗)
     * @return 列元数据
     */
    List<ColumnMeta> getColumn(DataSource ds, String catalog, String tableName, boolean needColumnType);
}
